﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using System.Reflection;
using System.IO;

namespace Genuilder.Extensibility.Targets
{
	public class ExtensibilityTask : AppDomainIsolatedTask, IExtensibilityTask
	{
		public ExtensibilityTask()
		{
		}
		#region IExtensibilityTask Members

		public string OutputPath
		{
			get;
			set;
		}

		public string Data
		{
			get;
			set;
		}


		public ITaskItem[] Sources
		{
			get;
			set;
		}

		[Output]
		public ITaskItem[] OutputSources
		{
			get;
			set;
		}

		public ITaskItem[] References
		{
			get;
			set;
		}

		#endregion

		public override bool Execute()
		{
			NormalizeProperties();
			try
			{
				FileCodeItemMementoRepository mementos = new FileCodeItemMementoRepository(new System.IO.FileInfo(Data));
				DirectoryCodeRepository repository = new DirectoryCodeRepository(mementos);
				if(OutputPath != null)
					repository.BaseDirectory = new DirectoryInfo(OutputPath);
				repository.Files.AddRange(Sources.Select(s => PathUtil.RelativePathTo(repository.BaseDirectory.FullName,new FileInfo(s.ItemSpec).FullName)));
				//List<string> sources = new List<string>();
				//repository.CodeTracked += (i) => sources.Add(i.FileName);
				var plugins = GetPlugins();
				var msbuildPlugin = new MSBuildPlugin(Sources);
				msbuildPlugin.OutputPath = OutputPath;
				plugins.Add(msbuildPlugin);
				foreach(var plugin in plugins)
				{
					plugin.Initialize(repository);
				}

				repository.Initialize();
				OutputSources = msbuildPlugin.OutputSources;
				return true;
			}
			catch(Exception ex)
			{
				Log.LogError(String.Format("Error when Genuilder.Extensibility runned : {0} \r\n StackTrace : {1}", ex.Message, ex.StackTrace));
				return false;
			}
		}

		private void NormalizeProperties()
		{
			if(References == null)
				References = new TaskItem[0];
			if(Sources == null)
				Sources = new TaskItem[0];
		}

		private List<IPlugin> GetPlugins()
		{
			var assemblies = References
				.Where(r => r.ItemSpec.EndsWith("Gen.dll"))
				.Select(r => Assembly.LoadFrom(GetAbsolute(r.ItemSpec)));


			//foreach(var assembly in assemblies)
			//{
			//    var directory = new FileInfo(assembly.Location).Directory.FullName;
			//    AppDomain.CurrentDomain.SetupInformation.PrivateBinPath += ";" + directory;
			//}

			var plugins = assemblies.SelectMany(a => a.GetTypes()
					.Where(t => typeof(IPlugin).IsAssignableFrom(t)))
					.Select(t => Activator.CreateInstance(t));
			return plugins.OfType<IPlugin>().ToList();
		}

		private string GetAbsolute(string relativeFile)
		{
			return Path.Combine(Directory.GetCurrentDirectory(), relativeFile);
		}
	}
}
